#include <stdlib.h>

#include "acts.h"

char act_failure[] = "Nit failed act";

static void
action_free(void *action, void *extra)
{
	(void) extra;
	free(action);
}

Disposer action_dspr = {
	.dispose = action_free
};

Nit_error
acts_init(Acts *acts)
{
	return map_init(acts, &action_dspr, 0);
}

Nit_error
acts_add(Acts *acts, uint32_t key_len, const void *key,
	 Act_do do_it, Act_undo undo, Act_dif dif)
{
	Nit_error error;
	Action *action = malloc(sizeof(*action));

	if (!action)
		return NIT_ERROR_MEMORY;

	action->do_it = do_it;
	action->undo = undo;
	action->dif = dif;

	if ((error = map_add(acts, key_len, key, action)))
		free(action);

	return error;
}

Nit_error
acts_act(Acts *acts, Act *act, void *extra)
{
	Action *action;

	if (!map_get(acts, act->key_len, act->key, (void **) &action))
		return NIT_ERROR_NOT_FOUND;

	switch (act->type) {
	case ACT_DO:
	case ACT_REDO:
		if (!action->do_it)
			return NIT_ERROR_NOT_DOABLE;

		if ((act->cng = action->do_it(act->real, act->dat,
					    act->args, extra)) == act_failure)
			return NIT_ERROR_FAILED;

		break;
	case ACT_UNDO:
		if (!action->undo)
			return NIT_ERROR_NOT_UNDOABLE;

		if ((action->undo(act->cng, act->dat, act->args, extra)))
			return NIT_ERROR_FAILED;

		break;
	case ACT_DIF:
	case ACT_REDIF:
		if (!action->dif)
			return NIT_ERROR_NOT_DIFF;

		if ((act->cng = action->dif(act->cng, act->dat,
					  act->args, extra)) == act_failure)
			return NIT_ERROR_FAILED;

		break;
	}

	return NIT_ERROR_FINE;
}
